import { isNumber } from "@tarojs/shared";
import dayjs, { Dayjs } from "dayjs";
import duration from "dayjs/plugin/duration";
import setting from "./setting";

dayjs.extend(duration);

export const richTextFormater = (val?: string) => {
  if (val && val.trim?.()) {
    return val.replace(/<img([^>]*?)>/g, function (match, group1) {
      // 查找 style 属性
      const hasStyle = group1.includes('style="');

      if (hasStyle) {
        // 如果有 style 属性，替换为自定义的 style
        return match.replace(
          /style="[^"]*"/,
          'style="max-width:100%;height:auto;"'
        );
      } else {
        // 如果没有 style 属性，添加自定义的 style
        return `<img${group1} style="max-width:100%;height:auto;">`;
      }
    });
  }

  return val;
};

/**
 * 处理 prop ，加单位
 * @param size
 * @returns
 */
export const suffixUnit = (size?: number | string) => {
  if (size) {
    return isNumber(size) ? size + "rpx" : size;
  }
};

/**
 * 获取扩展名
 * @param filename
 * @returns
 */
export function getFileExtension(filename: string) {
  // 使用正则表达式匹配扩展名（不包括点）
  const extension = filename.match(/\.([^.]+)$/);
  // 如果匹配到扩展名，则返回扩展名部分；否则返回空字符串
  return extension ? extension[1] : "";
}

/**
 * 获取距离当前时间有多久
 * 使用 getTimeDiffFromNow
 * @param stamp
 * @returns
 */
export function formatTimeElapsed(stamp?: number | string) {
  if (stamp) {
    const date1 = dayjs();

    const date2 = isNumber(stamp) ? dayjs.unix(stamp) : dayjs(stamp);

    const diffs = date1.diff(date2, "minute");
    const type = diffs < 120 ? 0 : diffs < 1440 ? 1 : 2;

    return type == 0
      ? diffs + "分钟"
      : type == 1
      ? Math.floor(diffs / 60) + "小时"
      : Math.floor(diffs / 1440) + "天";
  }
  return "";
}

/**
 * 将秒数转换为指定的时间单位
 * @param {number} value - 秒数
 * @param {Array<string>} types - 需要转换的时间单位数组，如 ["day", "hour", "min"]
 * @returns {Object} 包含转换后时间单位的对象
 */
export function convertSeconds(value: number, types: string[] = []) {
  const result = {
    day: 0,
    hour: 0,
    min: 0,
    sec: 0,
  };

  // 定义转换关系
  const conversions = {
    day: 86400, // 1天 = 86400秒
    hour: 3600, // 1小时 = 3600秒
    min: 60, // 1分钟 = 60秒
    sec: 1, // 1秒 = 1秒
  };

  // 确保types是数组且不为空
  const validTypes =
    Array.isArray(types) && types.length > 0 ? types : ["hour", "min", "day"];

  let remainingSeconds = value;

  // 按照从大到小的单位顺序处理
  const sortedTypes = validTypes.sort(
    (a, b) => conversions[b] - conversions[a]
  );

  sortedTypes.forEach((type) => {
    if (conversions.hasOwnProperty(type)) {
      const divisor = conversions[type];

      result[type] = Math.floor(remainingSeconds / divisor);
      remainingSeconds = remainingSeconds % divisor;
    }
  });

  return result;
}

type TimeUnit = "day" | "hour" | "minute";

interface TimeDiffResult {
  isFuture: boolean; // true=未来时间，false=过去时间
  day?: number; // 始终为正整数
  hour?: number;
  minute?: number;
  second?: number;
}

/**
 * 返回当前时间与指定时间的差值
 * formatTimeElapsed 的增强版
 * @param time
 * @param units
 * @returns
 */
export function getTimeDiffFromNow(
  time: number | string | Dayjs,
  units: TimeUnit[] = ["day", "hour", "minute"]
): TimeDiffResult | undefined {
  const targetTime = dayjs(time);
  if (!targetTime.isValid()) {
    return undefined;
  }

  const now = dayjs();
  /**
   * 判断目标时间是否为未来时间
   */
  const isFuture = targetTime.isAfter(now);
  const diffInMs = Math.abs(now.diff(targetTime)); // 取绝对值
  const durationObj = dayjs.duration(diffInMs);

  const result: TimeDiffResult = { isFuture };

  if (units.includes("day")) {
    result.day = Math.floor(durationObj.asDays());
  }
  if (units.includes("hour")) {
    result.hour = durationObj.hours();
  }
  if (units.includes("minute")) {
    result.minute = durationObj.minutes();
  }

  return result;
}

/**
 * 对象转换为符合路由 search 字符串（即 URL 查询字符串）
 * (小程序不支持URLSearchParams)
 * @param obj Record<string, string | number | boolean>
 * @returns
 */
export function objectToQueryString(
  obj: Record<string, string | number | boolean | undefined | null>
) {
  return Object.entries(obj)
    .flatMap(([key, value]) => {
      if (value === undefined || value === null) return [];
      if (Array.isArray(value)) {
        return value.map((v) => `${key}=${v}`);
      }
      return `${key}=${value}`;
    })
    .join("&");
}

/**
 * 校验并补全URL地址
 * @param {string} url - 要校验的目标地址
 * @param {string} [defaultProtocol='https'] - 默认协议（当需要补全时使用）
 * @returns {string} 完整的URL地址
 */
export function ensureCompleteUrl(url) {
  // 检查是否已经是完整URL（以http://或https://开头）
  if (/^https?:\/\//i.test(url)) {
    return url;
  }

  // 移除开头可能存在的斜杠
  const cleanedUrl = url.replace(/^\/+/, "");

  // 加上域名地址
  return `${setting.host}/uploads/${cleanedUrl}`;
}

/**
 * 挑选对象的指定属性，并重命名 key。
 * @param {object} obj - 源对象
 * @param {object} keyMap - 键名映射表 { 旧key: 新key }
 * @returns {object} 新对象
 */
export const pickTransMap = (obj, keyMap) => {
  return Object.fromEntries(
    Object.entries(keyMap)
      .filter(([oldKey]) => oldKey in obj)
      .map(([oldKey, newKey]) => [newKey, obj[oldKey]])
  );
};

/**
 * 计算两个时间之间一共多少天（包含第一天和最后一天）
 * @param start
 * @param end
 * @returns
 */
export function getDaysBetweenDate(start: string | Dayjs, end: string | Dayjs) {
  return dayjs(end).diff(dayjs(start), "day") + 1;
}

/**
 * 根据开始时间、周期、节假日状态计算周期结束时间
 * @param start 开始时间
 * @param period 施工时长
 * @param holidayList 假日时间
 * @param isSkipHoliday 节假日是否施工 true 不施工，false 施工
 */
export function getPeriodEndDate(
  start,
  // 施工时长
  period: number,
  holidayList: number[] = [],
  // 是否跳过节假日
  isSkipHoliday?: boolean
) {
  // 1. 校验输入
  if (period <= 0) throw new Error("工期必须大于 0");
  const target = dayjs(start);
  if (!target.isValid()) throw new Error("开始时间无效");

  // 2. 如果不跳过节假日，直接计算结束时间
  if (!isSkipHoliday || holidayList.length === 0) {
    return target.add(period - 1, "day"); // period=1 => 当天
  }

  // 3. 跳过节假日逻辑
  let remainingDays = period - 1; // 剩余需计算的天数
  let currentTarget = target.clone();
  let holidayIndex = 0;

  while (remainingDays > 0 && holidayIndex < holidayList.length) {
    const nextHoliday = dayjs(holidayList[holidayIndex]);

    // 跳过已过去的节假日
    if (nextHoliday.isBefore(currentTarget, "day")) {
      holidayIndex++;
      continue;
    }

    // 计算当前目标到下一个节假日之间的天数
    const daysToHoliday = nextHoliday.diff(currentTarget, "day");
    const effectiveDays = Math.min(remainingDays, daysToHoliday);

    if (effectiveDays > 0) {
      currentTarget = currentTarget.add(effectiveDays, "day");
      remainingDays -= effectiveDays;
    }

    // 如果剩余天数未用完，且当前正好是节假日，跳过
    if (remainingDays > 0 && nextHoliday.isSame(currentTarget, "day")) {
      currentTarget = currentTarget.add(1, "day");
      holidayIndex++;
    }
  }

  // 4. 处理剩余天数（无节假日干扰）
  if (remainingDays > 0) {
    currentTarget = currentTarget.add(remainingDays, "day");
  }

  return currentTarget;
}
